package node

import (
	"encoding/json"
	"framework/remote"
	"go.uber.org/zap"
)

type App struct {
	name      string
	remoteCli remote.Client
	readChan  chan []byte
	writeChan chan *remote.Msg
	handlers  LogicHandler
}

func Default(name string) *App {
	return &App{
		name:      name,
		readChan:  make(chan []byte, 1024),
		writeChan: make(chan *remote.Msg, 1024),
		handlers:  make(LogicHandler), //map初始化
	}
}

/*
*
node app 启动
*/
func (a *App) Run(serverId string) error {
	//1 初始化natsclient
	a.remoteCli = remote.NewNatsClient(serverId, a.readChan)
	//2 启动nats client
	err := a.remoteCli.Run()
	if err != nil {
		return err
	}
	//2 启动读写协程
	go a.readChanMsg()
	go a.writeChanMsg()
	return nil
}

/*
*
读取数据
*/
func (a *App) readChanMsg() {
	//收到的是其他nats client发送的消息
	for {
		select {
		case info, ok := <-a.readChan:
			if ok {
				var remoteMsg remote.Msg
				err := json.Unmarshal(info, &remoteMsg)
				zap.S().Infof("%s appliation readChanMsg , receive Msg:%v", a.name, remoteMsg)
				if err != nil {
					zap.S().Errorf("readChanMsg json Unmarshal err:%v", err)
				}
				//根据route进行处理，得到返回的结果
				router := remoteMsg.Router
				session := remote.NewSession(a.remoteCli, &remoteMsg)
				handlerFunc, ok := a.handlers[router]
				if ok {
					result := handlerFunc(session, remoteMsg.Body.Data)
					newBody, _ := json.Marshal(result)
					message := remoteMsg.Body
					message.Data = newBody
					responseMsg := &remote.Msg{
						Cid:  remoteMsg.Cid,
						Body: message,
						Src:  remoteMsg.Dst,
						Dst:  remoteMsg.Src,
						Uid:  remoteMsg.Cid,
					}
					a.writeChan <- responseMsg
				}

			}
		}
	}
}

/*
*
发送数据
*/
func (a *App) writeChanMsg() {
	for {
		select {
		case msg, ok := <-a.writeChan:
			if ok {
				zap.S().Infof("%s appliation writeChanMsg , send %v to dst:%v,", a.name, msg, msg.Dst)
				marshal, _ := json.Marshal(msg)
				err := a.remoteCli.SendMsg(msg.Dst, marshal)
				if err != nil {
					zap.S().Errorf("app writeChanMsg err:%v", err)
				}
			}
		}
	}
}

func (a *App) Close() {
	if a.remoteCli != nil {
		a.remoteCli.Close()
	}
}

/*
*
注册handler
*/
func (a *App) RegisterHandler(handler LogicHandler) {
	a.handlers = handler
}
